//
//  ViewController.m
//  ThreadDemo
//
//  Created by liuxiang on 2017/12/27.
//  Copyright © 2017年 liuxiang. All rights reserved.
//

#import "ViewController.h"
const char *queueLabel = "ThreadDemoQueue";

@interface MyOperation: NSOperation

@property (strong, nonatomic) void(^operationComplationBlock)(id result);


@end


@implementation MyOperation

@synthesize finished = _finished;
@synthesize executing = _executing;

- (instancetype)init
{
    self = [super init];
    if (self) {
        _executing = NO;
        _finished = NO;
    }
    return self;
}

- (BOOL) isConcurrent {
    return YES;
}

- (BOOL) isFinished {
    return _finished;
}

- (BOOL) isExecuting {
    return _executing;
}

- (void)setFinished:(BOOL)finished {
    [self willChangeValueForKey:@"isFinished"];
    _finished = finished;
    [self didChangeValueForKey:@"isFinished"];
}

- (void)setExecuting:(BOOL)executing {
    // 手动触发KVO
    [self willChangeValueForKey:@"isExecuting"];
    _executing = executing;
    [self didChangeValueForKey:@"isExecuting"];
}


- (void) start {
    if ([self isCancelled]) {
        [self willChangeValueForKey:@"isFinished"];
        _finished = YES;
        [self didChangeValueForKey:@"isFinished"];
        return;
    }
    [self willChangeValueForKey:@"isExecuting"];
//    [NSThread detachNewThreadSelector:@selector(main) toTarget:self withObject:nil];
    dispatch_queue_t queue = dispatch_queue_create(queueLabel, DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        [self main];
    });
    _executing = YES;
    [self didChangeValueForKey:@"isExecuting"];
}

- (void) main {
    @try {
        @autoreleasepool{
            NSLog(@"main");
            [self completeOperation];
        }
    }
    @catch(NSException *exp) {
        NSLog(@"exp = %@",exp);
    }
}

- (void)completeOperation {
    self.executing = NO;
    self.finished = YES;
    if (self.operationComplationBlock) {
        self.operationComplationBlock(@"df");
    }
}

- (void)dealloc
{
    NSLog(@"dealloc");
}

@end

@interface ViewController ()

@end

@implementation ViewController

{
    dispatch_source_t _timer;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    [self operationQueue];
//    [self dispathQueue];
//    [self dispathSoure];
    
}

- (void) thread {
    // NSThread 创建线程
    //创建一个脱离的线程，并启动
    [NSThread detachNewThreadSelector:@selector(threadSelector:) toTarget:self withObject:@(10)];
    // 创建一个脱离的线程
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadSelector:) object:@(10)];
    // 手动调用start方法
    thread.name = @"thread";
    [thread start];
    // 脱离的线程：当线程退出的时候线程的资源由系统自动回收。这也同样意味着之后不需要在其他线程里面显式的连接(join)。
}

- (void) operationQueue {
    NSBlockOperation *blockOperation0 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"this is 0");
        
    }];
    [blockOperation0 setCompletionBlock:^{
        NSLog(@"blockOperation0 completion");
    }];
    
    NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"this is NSBlockOperation");
        NSArray *array = @[@"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9",@"10"];
        //        [array enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        //            NSLog(@"obj = %@, idx = %d",obj,idx);
        //        }];
        for (NSString *str in array) {
            NSLog(@"str = %@",str);
        }
    }];
    [blockOperation0 addObserver:self forKeyPath:@"isExecuting" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];
    [blockOperation0 setQueuePriority:NSOperationQueuePriorityHigh];
    [blockOperation0 setQualityOfService:NSQualityOfServiceDefault];
    //    [blockOperation0 waitUntilFinished];
    [blockOperation setCompletionBlock:^{
        NSLog(@"blockOperation completion");
    }];
    
    NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(invocationOperation) object:nil];
    [invocationOperation setCompletionBlock:^{
        NSLog(@"invocationOperation completion");
    }];
    //    [blockOperation start];
    
    NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
    // NSOperation 属性必须要在添加到queue之前设置，否则可能会不起作用
    // 挂起queue
    [operationQueue setSuspended:YES];
    [invocationOperation addDependency:blockOperation];
    
    [operationQueue addOperation:blockOperation];
    
    [operationQueue addOperation:invocationOperation];
    NSLog(@"will add blockOperation0");
    [operationQueue addOperation:blockOperation0];
    NSLog(@"did add blockOperation0");
    
    MyOperation *myOperation = [[MyOperation alloc] init];
//    [myOperation start];
    // 继续queue
    [operationQueue setSuspended:NO];
    [operationQueue addOperation:myOperation];
}

- (void) dispathQueue {
    //绝对不要在任务中调用 dispatch_sync 或 dispatch_sync_f 函数，并同步 dispatch 新任务到当前正在执行的 queue。对于串行 queue 这一点特别重要，因 为这样做肯定会导致死锁;而并发 queue 也应该避免这样做。
    /*
    dispatch_queue_t myCustomQueue;
    myCustomQueue = dispatch_queue_create("com.example.MyCustomQueue",  );
    dispatch_async(myCustomQueue, ^{
        printf("Do some work here.\n");
        dispatch_sync(myCustomQueue, ^{
            printf("Do some more work here.\n");
        });
    });
    printf("The first block may or may not have run.\n");
    printf("Both blocks have completed.\n");
     */
    //获取全局并发queue
    dispatch_queue_t global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    // 创建串行queue
    dispatch_queue_t queue = dispatch_queue_create(queueLabel, DISPATCH_QUEUE_SERIAL);
    //循环遍历，如果是queue是并发的，则可能不是按顺讯的，串行的按顺序执行
    dispatch_apply(10, queue, ^(size_t i) {
        NSLog(@"i = %d",i);
    });
//    Dispatch Semaphore 信号量
    //初始信号量为1
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
    // 线程一
    dispatch_async(global_queue, ^{
        //降低信号量
        long count =  dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        //信号量1-1 = 0,其余线程阻塞（线程二不会执行）
        NSLog(@"count = %d",count);
        sleep(4);
        NSLog(@"sleep");
        //提高信号量
        count = dispatch_semaphore_signal(semaphore);
        //信号量0 + 1 = 1
        // 线程二执行
        NSLog(@"count = %d",count);
    });
    //线程二
    dispatch_async(global_queue, ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        NSLog(@"run task 2");
        sleep(1);
        NSLog(@"complete task 2");
        dispatch_semaphore_signal(semaphore);
    });
    //降低信号量
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    //信号量1-1 = 0，阻塞其他线程（线程一和线程二阻塞）
    NSLog(@"excute complation");
    sleep(3);
    //提高信号量
    dispatch_semaphore_signal(semaphore);
    //信号量0+1 = 1,执行线程一或者线程二
    // 当信号量小于等于0时就会阻塞其他线程，当信号量大于0时，其他线程就会执行。初始信号量在初始化的传入。
    //信号量的增加和减少要成对出现，否则可能会出现一些bug。
}

- (void) dispathSoure {
    NSArray *array = @[@"123",@"456"];
    //获取全局并发queue
    dispatch_queue_t global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    // 创建串行queue
//    dispatch_queue_t queue = dispatch_queue_create(queueLabel, DISPATCH_QUEUE_SERIAL);
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, global_queue);
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
    void *context = (void *)CFBridgingRetain(array);
    // 设置上下文，传递自定义数据
    dispatch_set_context(timer, context);
    dispatch_source_set_event_handler(timer, ^{
        NSLog(@"hello world");
    });
    // 获取上下文，获取自定义数据
   CFTypeRef arrayref = (CFTypeRef *)dispatch_get_context(timer);
    NSArray *array1 = CFBridgingRelease(arrayref);
    NSLog(@"array 1= %@",array1);
    dispatch_source_set_cancel_handler(timer, ^{
        NSLog(@"timer cancel");
    });
    dispatch_resume(timer);
    //成员变量延长生命周期，防止被释放，导致不会执行
    _timer = timer;
}

- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    if ([keyPath isEqualToString:@"isExecuting"]) {
        NSLog(@"old value = %@,new value = %@",change[NSKeyValueChangeOldKey],change[NSKeyValueChangeNewKey]);
    }
}

#pragma mark - Thread Methods
- (void) threadSelector:(NSNumber *)num {
    
    for (int i = 0; i < num.intValue; i++) {
        NSLog(@" i = %d， name = %@",i,[NSThread currentThread].name);
    }
}

- (void) invocationOperation {
    NSLog(@"thread = %@",[NSThread currentThread]);
    NSLog(@"invocationOperation");
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end
